package pwd.allen.springboot.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * 定义监听器
 * 接收参数的类型要和发送时的一致，否则可能导致参数转换报错
 **/
@Slf4j
@Component
public class MyListener {

    public static final String QUEUE = "topic_exchange_boot_queue_1";
    public static final String SIMPLE_QUEUE = "simple_queue";
    public static final String EXCHANGE = "topic_exchange_boot";
    public static final String ROUTINGKEY = "boot.#";

    /**
     * 如果队列交换机不存在 会自动创建（如果要禁止自动创建，则设置 spring.rabbitmq.dynamic = false）
     * @param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = QUEUE, durable = "true"),
            exchange = @Exchange(value = EXCHANGE, type = ExchangeTypes.TOPIC),
            key = {ROUTINGKEY}))
    public void listen(Map<String, String> msg){
        log.info("接收到{}消息：{}", QUEUE, msg);
    }

    /**
     * 这个好像不会创建队列，故在 {@link pwd.allen.springboot.config.MqConfig} 中创建该队列
     *
     * 使用@RabbitHandler注解标注的方法要增加 channel(信道)、message 两个参数
     *
     * TODO spring.rabbitmq.listener.simple.acknowledge-mode=manual
     *
     * @param msg
     */
    @RabbitListener(queues = SIMPLE_QUEUE)
    @RabbitHandler
    public void listen(String msg, Channel channel, Message message) throws IOException {
        log.info("接收到{}消息：{}", SIMPLE_QUEUE, msg);
        try {
            // 手动确认消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("消息确认失败", e);
            if (message.getMessageProperties().getRedelivered()) {

                log.error("消息已重复处理失败,拒绝再次接收...");

                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false); // 拒绝消息
            } else {

                log.error("消息即将再次返回队列处理...");

                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }
    }
}
